package com.winsdom.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.winsdom.anno.Authentication;
import com.winsdom.context.BaseContext;
import com.winsdom.exception.BaseException;
import com.winsdom.exception.BusinessException;
import com.winsdom.mapper.LoginMapper;
import com.winsdom.properties.JwtProperties;
import com.winsdom.result.Result;
import com.winsdom.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static com.winsdom.enums.RedisKey.USER_PERMISSION;

/**
 * JWT令牌拦截器
 * 用于验证用户身份和权限
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class JwtTokenInterceptor implements HandlerInterceptor {
    private AntPathMatcher pathMatcher = new AntPathMatcher();
    private final ObjectMapper objectMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private LoginMapper loginMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String path = request.getRequestURI();
        List<String> excludePaths = Arrays.asList(
                "/login", "/login/**", "/register", "/test/**",
                "/upload/**", "/swagger-ui/**", "/swagger-resources/**",
                "/doc.html", "/v2/api-docs/**", "/login/sendVerificationCode",
                "/api/alipay/toSuccess", // GET 同步跳转
                "/api/alipay/notify"   // POST 异步通知
        );

        for (String excludePath : excludePaths) {
            if (pathMatcher.match(excludePath, path)) {
                return true; // 匹配到排除路径，直接放行
            }
        }
        // 如果不是处理方法直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        log.info("拦截到请求: {}", request.getRequestURL());

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 获取方法和类上的Authentication注解
        Authentication methodAnnotation = handlerMethod.getMethodAnnotation(Authentication.class);
        Authentication classAnnotation = handlerMethod.getBeanType().getAnnotation(Authentication.class);

        // 获取请求头中的token
        String token = request.getHeader("Authorization");
        log.info("当前请求token: {}", token);
        if(token == null)
        {
            throw new BaseException("没有获取到token");
        }
        try {
            // 解析JWT令牌
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            // 获取用户id
            Integer userId = (claims.get("id", Long.class)).intValue();
            log.info("当前用户id:{}", userId);
            BaseContext.setCurrentId(userId);
            log.info("用户JWT校验, 用户ID: {}", userId);
            // 获取用户分类id
            Integer categoryId = (claims.get("categoryId", Long.class)).intValue();
            log.info("当前用户分类id:{}", categoryId);
            BaseContext.setCategoryId(categoryId);
            log.info("用户JWT校验, 用户分类ID: {}", categoryId);

            // 从redis中获取当前用户的权限
            String redisKey = USER_PERMISSION.getValue()+userId;
            List<String> permissions = (List<String>) redisTemplate.opsForValue().get(redisKey);
            if (permissions == null) {
                // 权限没有，去数据库在获取权限
                throw new BusinessException("该用户没有权限！", HttpStatus.BAD_REQUEST);
            }
            log.info("当前用户的权限{}", permissions);

            // 获取注解上的权限值
            String requiredPower = null;
            if (methodAnnotation != null) {
                requiredPower = Arrays.stream(methodAnnotation.value())
                        .map(Enum::name)
                        .collect(Collectors.joining(","));
            } else if (classAnnotation != null) {
                requiredPower = Arrays.stream(classAnnotation.value())
                        .map(Enum::name)
                        .collect(Collectors.joining(","));
            }

            // 权限判断
            if (requiredPower == null) {
                // 当注解未获取到权限值时，直接放行
                return true;
            }
            List<String> requiredPowerList = Arrays.asList(requiredPower.split(","));
            boolean allPermissionsPresent = true;
            for (String power : requiredPowerList) {
                if (!permissions.contains(power)) {
                    allPermissionsPresent = false;
                    break;
                }
            }
            if (allPermissionsPresent) {
                return true;
            } else {
                throw new BaseException("权限不足");
            }
        } catch (Exception e) {
            throw new BaseException("权限不足");
        }
    }

    /**
     * 将结果写入响应
     */
    private void writeResponse(HttpServletResponse response, Result result) throws IOException {
        String jsonString = objectMapper.writeValueAsString(result);
        response.getWriter().write(jsonString);
    }
}
